package com.such.kit.resource;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import com.such.kit.Callable;
import com.such.kit.Logger;
import com.such.kit.cache.CacheCommons;
import com.such.kit.file.FileCommons;
import com.such.kit.file.JarFileCommons;
import com.such.kit.resource.support.ReadResource;
import com.such.kit.resource.util.OrderedProperties;
import com.such.kit.stream.StreamCommons;
import com.such.kit.string.StringCommons;
import com.such.kit.validate.ValidateCommons;

/**
 * @author SUCH
 * <pre>
 * ReadProperties 是基于文件系统实现的 properties 资源文件操作工具类
 * 由于是基于文件系统的实现，ReadProperties 支持绝对路径或（classes）相对路径
 * {@link #resourceName} 可以取绝对路径、相对路径、类名(xxx.xxx.propertiesName)
 * 
 * 此工具类对 Properties 进行了继承、重写为 OrderedProperties，OrderedProperties 能够按照文件中内容先后保持顺序
 * 
 * [警告] 为了支持类名格式的 resourceName，系统会将 . 替换为 /
 * </pre>
 */
public class ReadProperties extends ReadResource {

	private static String propertiesCache = CacheCommons.buildCacheName(ReadProperties.class);

	/** resourceName：资源名 */
	private String resourceName;
	/** relatively：是否为相对路径 */
	private boolean relatively;

	/**
	 * <pre>
	 * [参考 {@link #ReadProperties(String, boolean)}]
	 * 
	 * relatively 默认为 false
	 * </pre>
	 */
	public ReadProperties(String resourceName) {
		this(resourceName, false);
	}

	/**
	 * @param resourceName [参考 {@link #resourceName}]
	 * @param relatively [参考 {@link #relatively}]
	 */
	public ReadProperties(String resourceName, boolean relatively) {
		this.resourceName = resourceName;
		this.relatively = relatively;
	}

	@Override
	public String getResourceName() {
		return this.resourceName;
	}

	@Override
	public List<String> getKeys() {
		List<String> keys = new ArrayList<String>();
		Set<String> keySet = getProperties().stringPropertyNames();
		if (ValidateCommons.isNotEmpty(keySet)) {
			keys.addAll(keySet);
		}
		return keys;
	}

	@Override
	public String getValue(String key) {
		return getProperties().getProperty(key);
	}

	@Override
	public Map<String, String> getValues() {
		Map<String, String> values = new HashMap<String, String>();
		for (String key : getKeys()) {
			values.put(key, getValue(key));
		}
		return values;
	}

	private Properties getProperties() {
		Properties properties = null;
		try {
			properties = CacheCommons.get(propertiesCache, this.resourceName, new Callable<String, Properties>() {
				@Override
				public Properties call(String param) throws RuntimeException {
					Properties properties = null;
					InputStream in = null;
					try {
						if (relatively) {
							String path = resourceName;

							int index = path.lastIndexOf(".");
							String enlargeName = "";
							if (index > -1) {
								enlargeName = path.substring(index + 1);
							}
							if ("properties".equals(enlargeName)) {
								path = path.substring(0, index);
							}

							// 处理 . 连接符将其转换为文件系统可识别的 / 分隔符
							path = StringCommons.merger(path.replace(".", FileCommons.COMPAT_SEPARATOR), ".properties");
							in = JarFileCommons.getResourceStream(path);
						} else {
							in = new FileInputStream(FileCommons.changeCompatSeparator(resourceName));
						}
						properties = new OrderedProperties();
						properties.load(in);
					} catch (Exception e) {
						Logger.error(ReadProperties.class, StringCommons.merger("未找到资源文件 [", resourceName, "]"), e);
					} finally {
						StreamCommons.closePure(in);
					}
					return properties;
				}
			});
		} catch (Exception e) {
			Logger.error(getClass(), "获取 Properties 异常", e);
		}
		return properties;
	}

}
